/**
 * 
 */
package wong.board.client.widgets;

import java.util.ArrayList;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.FlowPanel;

/**
 * @author wong
 * @see ComplexPanel
 * @see FlowPanel
 */
public class ContentForm extends ElementPanel implements Content, HasFormCallbacks {

	private ArrayList<FormCallback> callbacks;

	public ContentForm() {
		super((Element) Document.get().createFormElement().cast());

		divertFormEvents();
	}

	public final native boolean checkValidity() /*-{
		return this.@wong.board.client.widgets.ContentForm::getElement()()
				.checkValidity();
	}-*/;

	private final native void divertFormEvents() /*-{
		var formElement = this.@wong.board.client.widgets.ContentForm::getElement()();
		// SUBMIT
		if (formElement.onsubmit) {
			formElement.disabledSubmit = formElement.onsubmit;
		}
		var gwtForm = this;
		formElement.onsubmit = function() {
			var result = false;
			try {
				result = gwtForm.@wong.board.client.widgets.ContentForm::onSubmit()();
			} catch (ex) {
				console.error("submit>" + ex);
			}
			return result;
		};
		// RESET
		if (formElement.onreset) {
			formElement.disabledReset = formElement.onreset;
		}
		formElement.onreset = function() {
			try {
				gwtForm.@wong.board.client.widgets.ContentForm::onReset()();
			} catch (ex) {
				console.error("reset>" + ex);
			}
		};
		// INPUT
		if (formElement.oninput) {
			formElement.disabledInput = formElement.oninput;
		}
		formElement.oninput = function(evt) {
			try {
				gwtForm.@wong.board.client.widgets.ContentForm::onInput(Lcom/google/gwt/dom/client/NativeEvent;)(evt);
			} catch (ex) {
				console.error("input>" + ex);
			}
		};
		// CHANGE
		if (formElement.onchange) {
			formElement.disabledChange = formElement.onchange;
		}
		formElement.onchange = function(evt) {
			try {
				gwtForm.@wong.board.client.widgets.ContentForm::onChange(Lcom/google/gwt/dom/client/NativeEvent;)(evt);
			} catch (ex) {
				console.error("change>" + ex);
			}
		};
		// IVALID
		if (formElement.oninvalid) {
			formElement.disabledInvalid = formElement.oninvalid;
		}
		formElement.oninvalid = function() {
			try {
				gwtForm.@wong.board.client.widgets.ContentForm::onInvalid()();
			} catch (ex) {
				console.error("invalid>" + ex);
			}
		};
	}-*/;

	protected boolean onSubmit() {
		if (checkValidity()) {
			boolean doSubmit = false;
			for (FormCallback callback : callbacks) {
				boolean onSubmit = callback.onSubmit();
				if (onSubmit) {
					doSubmit = true;
				}
			}
			return doSubmit;
		}
		return false;
	}

	protected void onReset() {
		for (FormCallback callback : callbacks) {
			callback.onReset();
		}
	}

	protected void onInput(NativeEvent nativeEvent) {
		for (FormCallback callback : callbacks) {
			callback.onInput(nativeEvent);
		}
	}

	protected void onChange(NativeEvent nativeEvent) {
		for (FormCallback callback : callbacks) {
			callback.onChange(nativeEvent);
		}
	}

	protected void onInvalid() {
		for (FormCallback callback : callbacks) {
			callback.onInvalid();
		}
	}

	@Override
	public void addCallback(FormCallback callback) {
		if (callbacks == null) {
			callbacks = new ArrayList<FormCallback>();
		}
		callbacks.add(callback);
	}

	@Override
	public void removeCallback(FormCallback callback) {
		if (callbacks == null) {
			return;
		}
		callbacks.add(callback);
	}

	public interface FormCallback {

		boolean onSubmit();

		void onReset();

		void onInput(NativeEvent nativeEvent);

		void onChange(NativeEvent nativeEvent);

		void onInvalid();
	}

}
